package org.cybzacg.convert.factory;

import lombok.Getter;
import lombok.ToString;

/**
 * 工厂统计信息类
 * 用于记录转换器工厂的运行统计信息
 *
 * @author cybzacg.blog
 * @version 3.0
 * @since 3.0
 */
@Getter
@ToString
public class FactoryStatistics {

    /**
     * 总转换器数量
     */
    private final int totalConverters;

    /**
     * 启用的转换器数量
     */
    private final int enabledConverters;

    /**
     * 缓存大小
     */
    private final int cacheSize;

    /**
     * 类型映射大小
     */
    private final int typeMappingSize;

    /**
     * 支持的类型数量
     */
    private final int supportedTypes;

    /**
     * 总转换次数
     */
    private long totalConversions;

    /**
     * 成功转换次数
     */
    private long successfulConversions;

    /**
     * 失败转换次数
     */
    private long failedConversions;

    /**
     * 平均转换时间（纳秒）
     */
    private double averageConversionTime;

    /**
     * 最大转换时间（纳秒）
     */
    private long maxConversionTime;

    /**
     * 最小转换时间（纳秒）
     */
    private long minConversionTime;

    /**
     * 工厂创建时间
     */
    private final long createdTime;

    /**
     * 最后更新时间
     */
    private long lastUpdateTime;

    /**
     * 构造函数
     *
     * @param totalConverters 总转换器数量
     * @param enabledConverters 启用的转换器数量
     * @param cacheSize 缓存大小
     * @param typeMappingSize 类型映射大小
     * @param supportedTypes 支持的类型数量
     */
    public FactoryStatistics(int totalConverters, int enabledConverters,
                            int cacheSize, int typeMappingSize, int supportedTypes) {
        this.totalConverters = totalConverters;
        this.enabledConverters = enabledConverters;
        this.cacheSize = cacheSize;
        this.typeMappingSize = typeMappingSize;
        this.supportedTypes = supportedTypes;
        this.totalConversions = 0;
        this.successfulConversions = 0;
        this.failedConversions = 0;
        this.averageConversionTime = 0.0;
        this.maxConversionTime = 0;
        this.minConversionTime = Long.MAX_VALUE;
        this.createdTime = System.currentTimeMillis();
        this.lastUpdateTime = this.createdTime;
    }

    /**
     * 记录成功的转换
     *
     * @param conversionTime 转换时间（纳秒）
     */
    public synchronized void recordSuccessfulConversion(long conversionTime) {
        totalConversions++;
        successfulConversions++;
        updateConversionTimeStats(conversionTime);
        lastUpdateTime = System.currentTimeMillis();
    }

    /**
     * 记录失败的转换
     *
     * @param conversionTime 转换时间（纳秒）
     */
    public synchronized void recordFailedConversion(long conversionTime) {
        totalConversions++;
        failedConversions++;
        updateConversionTimeStats(conversionTime);
        lastUpdateTime = System.currentTimeMillis();
    }

    /**
     * 更新转换时间统计
     *
     * @param conversionTime 转换时间（纳秒）
     */
    private void updateConversionTimeStats(long conversionTime) {
        // 更新最大转换时间
        if (conversionTime > maxConversionTime) {
            maxConversionTime = conversionTime;
        }

        // 更新最小转换时间
        if (conversionTime < minConversionTime) {
            minConversionTime = conversionTime;
        }

        // 更新平均转换时间
        if (totalConversions > 0) {
            averageConversionTime = (averageConversionTime * (totalConversions - 1) + conversionTime) / totalConversions;
        }
    }

    /**
     * 获取成功率
     *
     * @return 成功率（0.0 - 1.0）
     */
    public double getSuccessRate() {
        if (totalConversions == 0) {
            return 0.0;
        }
        return (double) successfulConversions / totalConversions;
    }

    /**
     * 获取失败率
     *
     * @return 失败率（0.0 - 1.0）
     */
    public double getFailureRate() {
        if (totalConversions == 0) {
            return 0.0;
        }
        return (double) failedConversions / totalConversions;
    }

    /**
     * 获取启用率
     *
     * @return 启用率（0.0 - 1.0）
     */
    public double getEnabledRate() {
        if (totalConverters == 0) {
            return 0.0;
        }
        return (double) enabledConverters / totalConverters;
    }

    /**
     * 获取运行时间（毫秒）
     *
     * @return 运行时间
     */
    public long getUptime() {
        return System.currentTimeMillis() - createdTime;
    }

    /**
     * 获取平均转换时间（毫秒）
     *
     * @return 平均转换时间
     */
    public double getAverageConversionTimeMs() {
        return averageConversionTime / 1_000_000.0;
    }

    /**
     * 获取最大转换时间（毫秒）
     *
     * @return 最大转换时间
     */
    public double getMaxConversionTimeMs() {
        return maxConversionTime / 1_000_000.0;
    }

    /**
     * 获取最小转换时间（毫秒）
     *
     * @return 最小转换时间
     */
    public double getMinConversionTimeMs() {
        if (minConversionTime == Long.MAX_VALUE) {
            return 0.0;
        }
        return minConversionTime / 1_000_000.0;
    }

    /**
     * 重置转换统计信息
     */
    public synchronized void resetConversionStats() {
        totalConversions = 0;
        successfulConversions = 0;
        failedConversions = 0;
        averageConversionTime = 0.0;
        maxConversionTime = 0;
        minConversionTime = Long.MAX_VALUE;
        lastUpdateTime = System.currentTimeMillis();
    }

    /**
     * 创建统计信息的副本
     *
     * @return 统计信息副本
     */
    public FactoryStatistics copy() {
        FactoryStatistics copy = new FactoryStatistics(
            totalConverters, enabledConverters, cacheSize, typeMappingSize, supportedTypes
        );

        // 复制转换统计信息
        copy.totalConversions = this.totalConversions;
        copy.successfulConversions = this.successfulConversions;
        copy.failedConversions = this.failedConversions;
        copy.averageConversionTime = this.averageConversionTime;
        copy.maxConversionTime = this.maxConversionTime;
        copy.minConversionTime = this.minConversionTime;
        copy.lastUpdateTime = this.lastUpdateTime;

        return copy;
    }

    /**
     * 生成详细的统计报告
     *
     * @return 统计报告字符串
     */
    public String generateReport() {
        StringBuilder report = new StringBuilder();
        report.append("=== 转换器工厂统计报告 ===\n");
        report.append(String.format("总转换器数: %d\n", totalConverters));
        report.append(String.format("启用转换器数: %d (%.2f%%)\n", enabledConverters, getEnabledRate() * 100));
        report.append(String.format("缓存大小: %d\n", cacheSize));
        report.append(String.format("类型映射数: %d\n", typeMappingSize));
        report.append(String.format("支持类型数: %d\n", supportedTypes));
        report.append("\n--- 转换统计 ---\n");
        report.append(String.format("总转换次数: %d\n", totalConversions));
        report.append(String.format("成功转换次数: %d (%.2f%%)\n", successfulConversions, getSuccessRate() * 100));
        report.append(String.format("失败转换次数: %d (%.2f%%)\n", failedConversions, getFailureRate() * 100));
        report.append("\n--- 性能统计 ---\n");
        report.append(String.format("平均转换时间: %.2f ms\n", getAverageConversionTimeMs()));
        report.append(String.format("最大转换时间: %.2f ms\n", getMaxConversionTimeMs()));
        report.append(String.format("最小转换时间: %.2f ms\n", getMinConversionTimeMs()));
        report.append("\n--- 运行信息 ---\n");
        report.append(String.format("创建时间: %d\n", createdTime));
        report.append(String.format("最后更新: %d\n", lastUpdateTime));
        report.append(String.format("运行时间: %d ms\n", getUptime()));
        report.append("========================");

        return report.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;

        FactoryStatistics that = (FactoryStatistics) obj;
        return totalConverters == that.totalConverters &&
               enabledConverters == that.enabledConverters &&
               cacheSize == that.cacheSize &&
               typeMappingSize == that.typeMappingSize &&
               supportedTypes == that.supportedTypes &&
               totalConversions == that.totalConversions &&
               successfulConversions == that.successfulConversions &&
               failedConversions == that.failedConversions &&
               Double.compare(that.averageConversionTime, averageConversionTime) == 0 &&
               maxConversionTime == that.maxConversionTime &&
               minConversionTime == that.minConversionTime &&
               createdTime == that.createdTime &&
               lastUpdateTime == that.lastUpdateTime;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = totalConverters;
        result = 31 * result + enabledConverters;
        result = 31 * result + cacheSize;
        result = 31 * result + typeMappingSize;
        result = 31 * result + supportedTypes;
        result = 31 * result + (int) (totalConversions ^ (totalConversions >>> 32));
        result = 31 * result + (int) (successfulConversions ^ (successfulConversions >>> 32));
        result = 31 * result + (int) (failedConversions ^ (failedConversions >>> 32));
        temp = Double.doubleToLongBits(averageConversionTime);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (int) (maxConversionTime ^ (maxConversionTime >>> 32));
        result = 31 * result + (int) (minConversionTime ^ (minConversionTime >>> 32));
        result = 31 * result + (int) (createdTime ^ (createdTime >>> 32));
        result = 31 * result + (int) (lastUpdateTime ^ (lastUpdateTime >>> 32));
        return result;
    }
}
